package com.kun.framework.core.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.NamingCase;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.kun.framework.core.AbstractApplication;
import com.kun.framework.core.controller.AbstractController;
import com.kun.framework.core.exception.BizException;
import com.kun.framework.core.util.ComUtil;
import javafx.fxml.FXMLLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * 窗口单例工厂类
 *
 * @author gzc
 * @since 2024/8/6
 **/
public class StageSingletonFactory {
    private static final Logger log = LoggerFactory.getLogger(StageSingletonFactory.class);

    private static Function<String, URL> loadFunction;
    private static Class<? extends AbstractApplication> loader;

    public static void init(Class<? extends AbstractApplication> loader,
                            Function<String, URL> loadFunction) {
        StageSingletonFactory.loadFunction = loadFunction;
        StageSingletonFactory.loader = loader;
    }

    /**
     * 强引用集合
     */
    private static final Map<Class<?>, AbstractController> INSTANCE_MAP = new ConcurrentHashMap<>(16);

    public static <E extends AbstractController> E getInstance(Class<E> cls) {
        AbstractController instance = INSTANCE_MAP.get(cls);
        if (instance == null) {
            synchronized (StageSingletonFactory.class) {
                instance = INSTANCE_MAP.get(cls);
                if (instance == null) {
                    instance = addInstance(cls);
                }
            }
        }
        return (E) instance;
    }

    public static <E extends AbstractController> AbstractController addInstance(Class<E> cls) {
        AbstractController abstractController = INSTANCE_MAP.get(cls);
        if (abstractController == null) {
            synchronized (StageSingletonFactory.class) {
                 abstractController = INSTANCE_MAP.get(cls);
                if (abstractController == null) {
                    try {
                        abstractController = createInstance(cls);
                    } catch (Exception e) {
                        throw new BizException(StrUtil.format("创建实例【{}】失败", cls), e);
                    }
                }
            }
        }
        return abstractController;
    }

    public static synchronized <E extends AbstractController> E addInstance(E instance) {
        if (instance == null) {
            throw new BizException("实例为空");
        }
        AbstractController abstractController = INSTANCE_MAP.get(instance.getClass());
        // 如果未初始化则
        if (abstractController == null) {
            instance.runBeforeCallback();
        }
        INSTANCE_MAP.put(instance.getClass(), instance);
        return instance;
    }

    public static synchronized void removeInstance(Class<? extends AbstractController> cls) {
        if (cls != null) {
            INSTANCE_MAP.remove(cls);
        }
    }

    public static synchronized void startupBefore() {
        if (CollUtil.isNotEmpty(INSTANCE_MAP)) {
            INSTANCE_MAP.values().forEach((instance) -> ComUtil.jfxThreadRun(instance::runBeforeCallback));
        }
    }

    public static synchronized void stopCallback() {
        if (CollUtil.isNotEmpty(INSTANCE_MAP)) {
            INSTANCE_MAP.values().forEach((instance) -> ComUtil.jfxThreadRun(instance::stopCallback));
        }
    }

    public static Map<Class<?>, AbstractController> getInstanceMap() {
        return INSTANCE_MAP;
    }

    /**
     * 创建实例
     *
     * @param cls 类对象
     * @return 实例对象
     */
    private static <E extends AbstractController> E createInstance(Class<E> cls) throws Exception {
        E obj;
        // 根据类名获取fxml文件地址
        String fxmlName = convertFxmlName(cls);
        URL resource = loadFunction.apply(fxmlName);
        if (resource != null) {
            FXMLLoader fxmlLoader = new FXMLLoader(resource);
            fxmlLoader.load();
            obj = fxmlLoader.getController();
        } else {
            // 无参构造创建实例
            obj = cls.getDeclaredConstructor().newInstance();
        }

        // 回调函数
        obj.runBeforeCallback();
        return obj;
    }

    private static String convertFxmlName(Class<? extends AbstractController> cls) {
        String tempName = cls.getSimpleName().replace("Controller", "");
        String underlineCaseStr = NamingCase.toUnderlineCase(tempName);
        List<String> splitList = StrUtil.split(underlineCaseStr, StrPool.UNDERLINE);
        String fxmlFileName = "";
        if (splitList.size() == 1) {
            fxmlFileName = splitList.get(0);
        }
        if (splitList.size() > 1) {
            fxmlFileName = StrUtil.join("-", splitList);
        }
        return fxmlFileName + ".fxml";
    }

}
